#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "Collection.h"
#include "Class.h"
#include "Math.h"

#include "String.h"
#include "Error.h"

//---- Collection --------------------------------------------------------------

NewAbstractMetaImpl0(Collection,Container);

Collection::Collection()
{
}

Object *Collection::Clone()
{
	Collection *clone= (Collection*) New();
	clone->AddAll(this);
	return clone;
}

Object *Collection::Add(Object *)
{
	AbstractMethod("Add");
	return 0;
}

void Collection::AddVector(Object *va_(op1), ...)
{
	va_list ap;
	va_start(ap, va_(op1));
	register Object *op;

	Add(va_(op1));
	while (op= va_arg(ap, Object*))
		Add(op);
	va_end(ap);
}

void Collection::AddVector(va_list ap)
{
	register Object *op;

	while (op= va_arg(ap, Object*))
		Add(op);
}

Object *Collection::Remove(Object*)
{
	AbstractMethod("Remove");
	return 0;
}

Object *Collection::RemovePtr(Object *)
{
	AbstractMethod("RemovePtr");
	return 0;
}

void Collection::AddAll(Collection *col)
{
	Iter next(col);
	register Object *op;

	while (op= next())
		Add(op);
}

void Collection::RemoveAll(Collection *col)
{
	Iter next(col);
	register Object *op;

	while (op= next())
		Remove(op);
}

void Collection::FreeAll()
{
	Iter next(this);
	register Object *op;

	while (op= next()) {
		if (op= Remove(op)) {
			op->FreeAll();
			delete op;
		}
	}
}

void Collection::Empty(int)
{
	Iter next(this);
	register Object *op;

	while (op= next())
		Remove(op);
}

Collection *Collection::Collect(ObjPtrFun fp, void* Arg)
{
	Iter next(this);
	register Object *op;
	register Collection *cp= (Collection*) New();

	while (op= next())
		cp->Add((*fp)(this, op, Arg));
	return cp;
}

Collection *Collection::Select(BoolFun fp, void *Arg)
{
	Iter next(this);
	register Object *op;
	register Collection *cp= (Collection*) New();

	while (op= next())
		if ((*fp)(this, op, Arg))
			cp->Add(op);
	return cp;
}

Object *Collection::Detect(BoolFun fp, void *Arg)
{
	Iter next(this);
	register Object *op, *detectedOp= 0;

	while (op= next())
		if ((*fp)(this, op, Arg)) {
			detectedOp= op;
			break;
		}
	return detectedOp;
}

OStream& Collection::PrintOn(OStream& os)
{
	register Object *op;
	Iter next(this);
	int sz;

	Object::PrintOn(os);
	os << Size() SP;
	for (sz= 0; op= next(); sz++)
		if (! op->IsDeleted())
			os << op SP;
	return os NL;
}

IStream& Collection::ReadFrom(IStream& is)
{
	int sz;
	Object *op;

	Object::ReadFrom(is);
	is >> sz;
	for (int i= 0; i < sz; i++) {
		is >> op;
		Add(op);
	}
	return is;
}

int Collection::GrowBy(int capDelta)
{
	// answers a new capacity according to the desired capacity delta.
	// used to localize growth behaviour; may be adapted.

	if (capDelta < 0) {
		Error("GrowBy", "capDelta < 0");
		capDelta= Capacity();
	}
	return Size() + Math::Range(2, cMaxInt - Capacity(), capDelta);
}

//---- DeletedObject -----------------------------------------------------------

NewMetaImpl0(DeletedObject,Object);

DeletedObject::DeletedObject() : Object(eObjIsDeleted)
{
}

